package it.softphone.cmc;

import it.softphone.cmc.impl.ScriptletServiceClientImpl;
import it.softphone.cmc.impl.SystemServiceClientImpl;
import it.softphone.cmc.shared.entity.Account;
import it.softphone.cmc.shared.entity.EntityFactory;
import it.softphone.cmc.shared.entity.TenantUser;
import it.softphone.commons.exception.NullParameterException;
import it.softphone.commons.json.server.JSONObject;
import it.softphone.commons.json.server.JSONUtils;
import it.softphone.commons.json.server.converter.JSONDateConverter;
import it.softphone.commons.json.server.converter.JSONStringConverter;
import it.softphone.commons.service.LogAware;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;

import org.apache.commons.logging.LogFactory;

import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
import com.google.web.bindery.autobean.vm.Configuration;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import com.sun.jersey.multipart.FormDataMultiPart;

/**
 * 
 * @author softphone
 *
 */
public class CMCServiceManager implements LogAware {

	static {
		LogFactory
			.getFactory()
				.setAttribute("org.apache.commons.logging.Log", 
							"org.apache.commons.logging.impl.Jdk14Logger");
	}
	
	public interface JerseyCall<R> {
	
		R exec();
	}
	
	static {
		//JSONUtils.registerConverter( Key.class, new JSONKeyConverter() );		
		//JSONUtils.registerConverter( Blob.class, new JSONBlobConverter() );
		JSONUtils.registerConverter( java.util.Date.class, new JSONDateConverter() );
		JSONUtils.registerConverter( String.class, new JSONStringConverter() );

	}
	
	private String baseUrl;
	private String username;
	private String password;
	private Client client;
	
	public final EntityFactory ef;
	public final Configuration configuration;
	
	public CMCServiceManager() {

		Configuration.Builder builder = new Configuration.Builder();
		//builder.setCategories( AttributesCategory.class );
		
		configuration = builder.build();
		ef = AutoBeanFactorySource.create( EntityFactory.class );
		
	}

	public CMCServiceManager( String url, String username, String password ) {
		this();
		
		setBaseUrl(url);
		this.username = username;
		this.password = password;
		
		init();
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("CMCServiceManager [baseUrl=").append(baseUrl)
				.append(", username=").append(username).append(", password=")
				.append(password).append("]");
		return builder.toString();
	}

	public final void init() {
		if( baseUrl == null ) throw new IllegalStateException("baseUrl is null!");
		if( username == null ) throw new IllegalStateException("username is null!");
		
		ClientConfig config = new DefaultClientConfig();

		client = Client.create(config);
		
		client.addFilter(new HTTPBasicAuthFilter(getUsername(), getPassword()));
		
	}
	
	public <R> R call( JerseyCall<R> call ) {
		
		try {

			R result = (R)call.exec();
			
			//logger.info( result );

			return result;
			
		} catch (UniformInterfaceException e) {
			
			ClientResponse r = e.getResponse();
			
			logger.warn( String.format("ERROR status [%d]\n[%s]\n",  
								r.getClientResponseStatus().getStatusCode(), 
								r.getEntity(String.class)));
			
		}
		
		return null;
	}
	
	public final String getBaseUrl() {
		return baseUrl;
	}

	public final void setBaseUrl(String baseUrl) {
		if( baseUrl.endsWith("/")) {
			this.baseUrl = String.valueOf(baseUrl.toCharArray(), 0, baseUrl.length()-1);
			
		}
		else {	
			this.baseUrl = baseUrl;
		}
	}

	public final String getUsername() {
		return username;
	}

	public final void setUsername(String username) {
		this.username = username;
	}

	public final String getPassword() {
		return password;
	}

	public final void setPassword(String password) {
		this.password = password;
	}

	public final Client getClient() {
		return client;
	}

	public final void setClient(Client client) {
		this.client = client;
	}

	public final String getServiceUrl( String service) {
		if( service == null ) throw new NullParameterException("service");
		if( baseUrl == null ) throw new IllegalStateException("baseUrl is null!");
		
		final StringBuilder sb = 
					new StringBuilder(getBaseUrl())
						.append("/cmc/rest/service" );
		
		if( service.charAt(0)!='/' ) sb.append('/');
		
		return sb.append(service).toString();	
		
	}
	
	public static MultivaluedMap<String, String> emptyParams() {
		return new MultivaluedMapImpl();
	}
	

	public final ScriptletServiceClientImpl scriptletService = new ScriptletServiceClientImpl(this);
	public final SystemServiceClientImpl systemService = new SystemServiceClientImpl(this);

	
	

	@Deprecated
	public void updateTenant( final String name, final java.io.File resource) {
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
				FormDataMultiPart multiPart = new FormDataMultiPart().field("logo",
						resource, MediaType.valueOf("image/png")).field("name",
						name);

				return client.resource(getBaseUrl() + "tenant")
						.type(MediaType.MULTIPART_FORM_DATA_TYPE)
						.put(String.class, multiPart);
				
			}
		});		

	}

	@Deprecated
	public void updateTenant( final String name, final String resource) {
		
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
				java.io.InputStream is = getClass().getClassLoader()
				.getResourceAsStream(resource);

				FormDataMultiPart multiPart = new FormDataMultiPart().field("logo",
						is, MediaType.valueOf("image/png")).field("name", name);
		
				return client.resource(baseUrl + "tenant")
						.type(MediaType.MULTIPART_FORM_DATA_TYPE)
						.put(String.class, multiPart);
				
			}
			
		});
		
	}
	
	@Deprecated
	public void createTenant( final String name, final String resource) {
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
				java.io.InputStream is =  getClass().getClassLoader().getResourceAsStream(resource);

				FormDataMultiPart multiPart = new FormDataMultiPart().
			       field(
			           "logo",
			           is,
			           MediaType.valueOf("image/png"))
			           .field("name", name);
				
				return client.resource(baseUrl + "tenant").type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, multiPart);
				
			}
			
		} );
		
	}

	@Deprecated
	public void getTenantByAccount() {
		
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
								
				return client.resource(getServiceUrl("tenant")).get(String.class);
				
			}
			
		});

	}
	
	public void login() {
		
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
								
				return client.resource(getServiceUrl("account/login")).get(String.class);
				
			}
			
		});

	}
	public void getLoggedAccount() {
	
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
								
				return client.resource(getServiceUrl("account")).get(String.class);
				
			}
			
		});

	}
	
	@Deprecated
	public void createAccount( Account a ) throws Exception {
		//scriptletService.saveScript("createAccount", Scriptlet.TYPE_JSON);
		//scriptletService.execScriptJSON( "createAccount", a);
		
	}

	@Deprecated
	public void createUser( final it.softphone.commons.json.server.JSONObject  u ) throws Exception {

		call( new JerseyCall<String>() {

			@Override
			public String exec() {
				MultivaluedMap<String, String> params = new MultivaluedMapImpl();
				params.putSingle("json", u.toString() );
				
				return client.resource(getServiceUrl("user"))
										.type("application/x-www-form-urlencoded")
										.post(String.class, params);
				
				//saveScript("createUser", Scriptlet.TYPE_JSON);
				//execScriptJSON( "createUser", a);
				
			}
			
		} );

		
		
	}
	
	@Deprecated
	public void createUser( TenantUser a ) throws Exception {
		
		createUser( new JSONObject(a) );
	}

	@Deprecated
	public void registerUser( final Object param ) throws Exception {
		
		call( new JerseyCall<String>() {

			@Override
			public String exec() {
				MultivaluedMap<String, String> params = new MultivaluedMapImpl();
				params.putSingle("json", JSONUtils.toJSON(param) );
				
				return client.resource(getServiceUrl("user/register"))
									.post(String.class,params);
				
			}
			
		} );
		
		
	}
	
}
